package Principal;

import java.awt.Color;
import java.awt.Component;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

public class Principal extends javax.swing.JFrame {
    File fXMLTemp;

    /** Creates new form Principal */
    public Principal() {
        initComponents();
        jtArbol.setCellRenderer(new MyRenderer());
        cambiarIcono();
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        jbgGrupo.add(rbDOM);
        jbgGrupo.add(rbSAX);
        jtArbol.setModel(null);
    }

    private void cambiarIcono() {
        DefaultTreeCellRenderer render= (DefaultTreeCellRenderer)jtArbol.getCellRenderer();
        render.setLeafIcon(null);
        render.setOpenIcon(null);
        render.setClosedIcon(null);
    }

    public void cargarRaiz(String stNombre){
        DefaultMutableTreeNode nodo = new DefaultMutableTreeNode(new MyNode(stNombre, -1));
        modelo = new DefaultTreeModel(nodo);
        nodosPadre.add(nodo);
    }

    public void agregarTag(String stNombre, tipoTAG ttTAG, int niColor){
      DefaultMutableTreeNode nodo;
      switch (ttTAG){
        case NIVEL: {
          nodo = new DefaultMutableTreeNode(new MyNode(stNombre, niColor));
          nodoPadre = (DefaultMutableTreeNode) nodosPadre.get(nodosPadre.size() - 1);
          modelo.insertNodeInto(nodo, nodoPadre, nodoPadre.getChildCount());
          break;
        }
        case INICIO: {
          nodo = new DefaultMutableTreeNode(new MyNode(stNombre, niColor));
          nodoPadre = (DefaultMutableTreeNode) nodosPadre.get(nodosPadre.size() - 1);
          modelo.insertNodeInto(nodo, nodoPadre, nodoPadre.getChildCount());
          nodosPadre.add(nodo);
          break;
        }
        case FIN:{
          nodo = new DefaultMutableTreeNode(new MyNode(stNombre, niColor));
          nodoPadre = (DefaultMutableTreeNode) nodosPadre.get(nodosPadre.size() - 1);
          nodosPadre.remove(nodoPadre);
          nodoPadre = (DefaultMutableTreeNode) nodosPadre.get(nodosPadre.size() - 1);
          modelo.insertNodeInto(nodo, nodoPadre, nodoPadre.getChildCount());
          break;
        }
      }
    }

    private void GetFileXML(String pRuta){
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("Seleccione archivo xml para analizar");
        fileChooser.setFileFilter(new XMLFileFilter());

        if (!pRuta.equals("")){
            fileChooser.setCurrentDirectory(new File(pRuta));
        }

        if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION){
           jtfRutaArchivo.setText(fileChooser.getSelectedFile().getPath());
        }
    }
    
    public void LanzarError(){
      Limpiar();
      JOptionPane.showMessageDialog(this, "Ocurrio un error al realizar el parseo", "ERROR",JOptionPane.ERROR_MESSAGE);
    }
    
    private void Limpiar(){
      jtfRutaArchivo.setText("");
      modelo = null;
      jtArbol.setModel(modelo);
      jbtIniciar.setText("Iniciar");
    }

    public void CrearNodo(String stCadena){
      DefaultMutableTreeNode nodo = new DefaultMutableTreeNode(stCadena);
      if (modif == tipoModif.NODO){
        modelo.insertNodeInto(nodo, (DefaultMutableTreeNode) nodoSeleccionado.getParent(), nodoSeleccionado.getParent().getIndex(nodoSeleccionado) + 1);
      }
      else if (modif == tipoModif.MODIFICO){
        DefaultMutableTreeNode[] nodosHijos = new DefaultMutableTreeNode[nodoSeleccionado.getChildCount()];

        for (int i= 0 ; i<nodosHijos.length ; i++){
          nodo.add((DefaultMutableTreeNode) nodoSeleccionado.getChildAt(0));
        }
        modelo.insertNodeInto(nodo, (DefaultMutableTreeNode) nodoSeleccionado.getParent(), nodoSeleccionado.getParent().getIndex(nodoSeleccionado));
        modelo.removeNodeFromParent(nodoSeleccionado);        
      }
    }

    private boolean Validar(){
        try {
          fXMLTemp = File.createTempFile("temp", ".xml");
          FileWriter fwWriter = new FileWriter(fXMLTemp);
          BufferedWriter oOutput = new BufferedWriter(fwWriter);
          Recorrer(oOutput, (DefaultMutableTreeNode) modelo.getRoot());
          oOutput.close();
          return true;
        } catch (IOException ex) {
            Logger.getLogger(Principal.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
    }

    private void Recorrer(BufferedWriter poOutput, DefaultMutableTreeNode pNodo) throws IOException{


      for (int i = 0 ; i<= pNodo.getChildCount() - 1 ; i++){
        poOutput.write(pNodo.getChildAt(i).toString());
        poOutput.newLine();
        Recorrer(poOutput, (DefaultMutableTreeNode) pNodo.getChildAt(i));
      }
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jbgGrupo = new javax.swing.ButtonGroup();
        jScrollPane1 = new javax.swing.JScrollPane();
        jtArbol = new javax.swing.JTree();
        jpnTope = new javax.swing.JPanel();
        jtfRutaArchivo = new javax.swing.JTextField();
        jpnTipoParser = new javax.swing.JPanel();
        rbSAX = new javax.swing.JRadioButton();
        rbDOM = new javax.swing.JRadioButton();
        jbtIniciar = new javax.swing.JButton();
        jbtAbrir = new javax.swing.JButton();
        jPanel4 = new javax.swing.JPanel();
        jtGuardar = new javax.swing.JButton();
        jtValidar = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jbtNuevoNodo = new javax.swing.JButton();
        jbtModificar = new javax.swing.JButton();
        jbtNuevoHijo = new javax.swing.JButton();
        jbtEliminar = new javax.swing.JButton();
        jbtComprimir = new javax.swing.JButton();
        jbtExpandir = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setMinimumSize(new java.awt.Dimension(675, 675));
        getContentPane().setLayout(null);

        jScrollPane1.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));

        jtArbol.setFont(new java.awt.Font("Courier New", 0, 18));
        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
        jtArbol.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        jtArbol.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
                jtArbolValueChanged(evt);
            }
        });
        jScrollPane1.setViewportView(jtArbol);

        getContentPane().add(jScrollPane1);
        jScrollPane1.setBounds(0, 100, 480, 540);

        jpnTope.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
        jpnTope.setMinimumSize(new java.awt.Dimension(0, 0));
        jpnTope.setLayout(null);

        jtfRutaArchivo.setFont(new java.awt.Font("Verdana", 0, 14));
        jtfRutaArchivo.setPreferredSize(new java.awt.Dimension(58, 27));
        jpnTope.add(jtfRutaArchivo);
        jtfRutaArchivo.setBounds(10, 10, 520, 30);

        jpnTipoParser.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Tipo de Parser", javax.swing.border.TitledBorder.CENTER, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Verdana", 0, 14))); // NOI18N
        jpnTipoParser.setFont(new java.awt.Font("Verdana", 0, 14));
        jpnTipoParser.setLayout(null);

        rbSAX.setFont(new java.awt.Font("Verdana", 0, 14));
        rbSAX.setSelected(true);
        rbSAX.setText("SAX ");
        jpnTipoParser.add(rbSAX);
        rbSAX.setBounds(10, 20, 60, 27);

        rbDOM.setFont(new java.awt.Font("Verdana", 0, 14));
        rbDOM.setText("DOM");
        jpnTipoParser.add(rbDOM);
        rbDOM.setBounds(70, 20, 60, 23);

        jpnTope.add(jpnTipoParser);
        jpnTipoParser.setBounds(390, 40, 140, 50);

        jbtIniciar.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtIniciar.setText("Iniciar");
        jbtIniciar.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtIniciarActionPerformed(evt);
            }
        });
        jpnTope.add(jbtIniciar);
        jbtIniciar.setBounds(540, 50, 123, 30);

        jbtAbrir.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtAbrir.setText("Abrir Archivo");
        jbtAbrir.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtAbrirActionPerformed(evt);
            }
        });
        jpnTope.add(jbtAbrir);
        jbtAbrir.setBounds(540, 10, 123, 30);

        getContentPane().add(jpnTope);
        jpnTope.setBounds(0, 0, 670, 100);

        jPanel4.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
        jPanel4.setLayout(null);

        jtGuardar.setFont(new java.awt.Font("Verdana", 0, 14));
        jtGuardar.setText("Guardar Cambios");
        jPanel4.add(jtGuardar);
        jtGuardar.setBounds(10, 500, 165, 30);

        jtValidar.setFont(new java.awt.Font("Verdana", 0, 14));
        jtValidar.setText("Validar Cambios");
        jtValidar.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jtValidarActionPerformed(evt);
            }
        });
        jPanel4.add(jtValidar);
        jtValidar.setBounds(10, 470, 165, 30);

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Gestión de nodos", javax.swing.border.TitledBorder.CENTER, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Verdana", 0, 14))); // NOI18N
        jPanel2.setLayout(null);

        jbtNuevoNodo.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtNuevoNodo.setText("Nuevo Nodo");
        jbtNuevoNodo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtNuevoNodoActionPerformed(evt);
            }
        });
        jPanel2.add(jbtNuevoNodo);
        jbtNuevoNodo.setBounds(10, 30, 135, 30);

        jbtModificar.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtModificar.setText("Modificar Nodo");
        jbtModificar.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtModificarActionPerformed(evt);
            }
        });
        jPanel2.add(jbtModificar);
        jbtModificar.setBounds(10, 90, 135, 30);

        jbtNuevoHijo.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtNuevoHijo.setText("Nuevo Hijo");
        jbtNuevoHijo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtNuevoHijoActionPerformed(evt);
            }
        });
        jPanel2.add(jbtNuevoHijo);
        jbtNuevoHijo.setBounds(10, 60, 135, 30);

        jbtEliminar.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtEliminar.setText("Eliminar Nodo");
        jbtEliminar.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtEliminarActionPerformed(evt);
            }
        });
        jPanel2.add(jbtEliminar);
        jbtEliminar.setBounds(10, 120, 135, 30);

        jPanel4.add(jPanel2);
        jPanel2.setBounds(20, 10, 155, 160);

        jbtComprimir.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtComprimir.setText("Comprimir Todo");
        jbtComprimir.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtComprimirActionPerformed(evt);
            }
        });
        jPanel4.add(jbtComprimir);
        jbtComprimir.setBounds(10, 410, 165, 30);

        jbtExpandir.setFont(new java.awt.Font("Verdana", 0, 14));
        jbtExpandir.setText("Expandir Todo");
        jbtExpandir.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtExpandirActionPerformed(evt);
            }
        });
        jPanel4.add(jbtExpandir);
        jbtExpandir.setBounds(10, 380, 165, 30);

        getContentPane().add(jPanel4);
        jPanel4.setBounds(480, 100, 190, 540);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jbtAbrirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtAbrirActionPerformed
      File fXML = null;

      if (jtfRutaArchivo.getText().trim().equals("")){
        GetFileXML("");
      }
      else{
        fXML = new File(jtfRutaArchivo.getText().trim());

        if ((fXML != null) && (fXML.exists())){
          GetFileXML(fXML.getAbsolutePath().toString());
        }
        else{
          GetFileXML("");
        }
      }
    }//GEN-LAST:event_jbtAbrirActionPerformed

    private void jbtIniciarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtIniciarActionPerformed
      if (jbtIniciar.getText().equals("Iniciar")){
        File fXML = new File(jtfRutaArchivo.getText().trim());

        if ((fXML != null) && (fXML.exists())){
          if (fXML.getAbsolutePath().substring(fXML.getAbsolutePath().length() - 4).equals(".xml")){
            Lanzador lanzadorDePrograma = new Lanzador(this);

            try {
              lanzadorDePrograma.ejecutar(rbSAX.isSelected(), fXML);
              jtArbol.setModel(modelo);
              jbtIniciar.setText("Limpiar");
            } catch (IOException ex) {
              JOptionPane.showMessageDialog(this, ex.getMessage(), "Error!", JOptionPane.ERROR_MESSAGE);
            }
          }
          else{
            JOptionPane.showMessageDialog(this, "Por favor seleccione un archivo XML", "Error!", JOptionPane.INFORMATION_MESSAGE);
          }
        }
      }
      else{
        Limpiar();
      } 
    }//GEN-LAST:event_jbtIniciarActionPerformed

    private void jbtComprimirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtComprimirActionPerformed
      for (int i = 0; i < jtArbol.getRowCount(); i++) {
         jtArbol.collapseRow(i);
      }
    }//GEN-LAST:event_jbtComprimirActionPerformed

    private void jbtExpandirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtExpandirActionPerformed
      for (int i = 0; i < jtArbol.getRowCount(); i++) {
         jtArbol.expandRow(i);
      }
    }//GEN-LAST:event_jbtExpandirActionPerformed

    private void jbtNuevoNodoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtNuevoNodoActionPerformed
      Modifica mod = null;
      if (!jtArbol.isSelectionEmpty()){
        if (nodoSeleccionado != (DefaultMutableTreeNode)modelo.getRoot()){
          mod = new Modifica(this, true, "");
          modif = tipoModif.NODO;
          mod.setVisible(true);
        }
      }
    }//GEN-LAST:event_jbtNuevoNodoActionPerformed

    private void jtArbolValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_jtArbolValueChanged
      TreePath path = evt.getPath();
      Object [] nodos = path.getPath();
      nodoSeleccionado = (DefaultMutableTreeNode) nodos[nodos.length - 1];
    }//GEN-LAST:event_jtArbolValueChanged

    private void jbtNuevoHijoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtNuevoHijoActionPerformed
      Modifica mod = null;
      if (!jtArbol.isSelectionEmpty()){
        if (nodoSeleccionado != (DefaultMutableTreeNode)modelo.getRoot()){
          mod = new Modifica(this, true, "");
          modif = tipoModif.HIJO;
          mod.setVisible(true);
        }
      }
    }//GEN-LAST:event_jbtNuevoHijoActionPerformed

    private void jbtModificarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtModificarActionPerformed
      Modifica mod = null;
      if (!jtArbol.isSelectionEmpty()){
        if (nodoSeleccionado != (DefaultMutableTreeNode)modelo.getRoot()){
          mod = new Modifica(this, true, nodoSeleccionado.toString());
          modif = tipoModif.MODIFICO;
          mod.setVisible(true);
        }
      }
    }//GEN-LAST:event_jbtModificarActionPerformed

    private void jbtEliminarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbtEliminarActionPerformed
      if (!jtArbol.isSelectionEmpty()){
        if (nodoSeleccionado != (DefaultMutableTreeNode)modelo.getRoot()){
          modelo.removeNodeFromParent(nodoSeleccionado);
        }
      }
    }//GEN-LAST:event_jbtEliminarActionPerformed

    private void jtValidarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jtValidarActionPerformed
      if (Validar() == true) {
      }
    }//GEN-LAST:event_jtValidarActionPerformed

    public static void main(String args[]) {
      try{
        javax.swing.UIManager.setLookAndFeel(
        UIManager.getSystemLookAndFeelClassName());
      }catch (Exception e){}

      java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
          new Principal().setVisible(true);
          }
      });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.ButtonGroup jbgGrupo;
    private javax.swing.JButton jbtAbrir;
    private javax.swing.JButton jbtComprimir;
    private javax.swing.JButton jbtEliminar;
    private javax.swing.JButton jbtExpandir;
    private javax.swing.JButton jbtIniciar;
    private javax.swing.JButton jbtModificar;
    private javax.swing.JButton jbtNuevoHijo;
    private javax.swing.JButton jbtNuevoNodo;
    private javax.swing.JPanel jpnTipoParser;
    private javax.swing.JPanel jpnTope;
    private javax.swing.JTree jtArbol;
    private javax.swing.JButton jtGuardar;
    private javax.swing.JButton jtValidar;
    private javax.swing.JTextField jtfRutaArchivo;
    private javax.swing.JRadioButton rbDOM;
    private javax.swing.JRadioButton rbSAX;
    // End of variables declaration//GEN-END:variables
    private DefaultMutableTreeNode nodoPadre = null;
    private DefaultMutableTreeNode nodoSeleccionado = null;
    private DefaultTreeModel modelo;
    private tipoModif modif = null;
    private List nodosPadre = new ArrayList<DefaultMutableTreeNode>();

    public enum tipoTAG{INICIO, FIN, NIVEL};
    public enum tipoModif{NODO, HIJO, MODIFICO};
}

class MyRenderer extends DefaultTreeCellRenderer {

    public MyRenderer() {
    }

    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
                                                  boolean expanded, boolean leaf, int row,
                                                  boolean hasFocus) {

        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

        switch (isTipoTag(value)){
            case 1:{
                setForeground(Color.RED);
                break;
            }
            case 2:{
                setForeground(new Color(33, 121, 23));
                break;
            }
            case 3:{
                setForeground(Color.BLACK);
                break;
            }
            case 4:{
                setForeground(Color.GRAY);
                break;
            }
            case 5:{
                setForeground(Color.BLUE);
                break;
            }
            case 6:{
                setForeground(new Color(0, 187, 167));
                break;
            }
            case 7:{
                setForeground(new Color(140, 55, 162));
                break;
            }
        }
        return this;
    }

    protected int isTipoTag(Object value) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
        MyNode nodeInfo = (MyNode) (node.getUserObject());
        return nodeInfo.getTipoTag();
        }
}

class MyNode{
    public MyNode(String pstNombre, int pniTipoTag){
        stNombre = pstNombre;
        niTipoTag = pniTipoTag;
    }

    public String getNombre(){
        return stNombre;
    }

    public int getTipoTag(){
        return niTipoTag;
    }

    public void setTipoTag(int pniTipoTag){
        niTipoTag = pniTipoTag;
    }

    public String toString(){
        return stNombre;
    }

    private String stNombre;
    private int niTipoTag;
}